

#include <ov5640_xclk.h>
#include <ov5640_bsp_msp.h>
#include <board.h>

/* Timer handler declaration */
static TIM_HandleTypeDef ov5640_tim_handle;

/* Timer Output Compare Configuration Structure declaration */
static TIM_OC_InitTypeDef sConfig;

int ov5640_xclk_init()
{
    /* GPIO Init */
    ov5640_xclk_msp_init();

    /* Counter Prescaler value */
    uint32_t uhPrescalerValue = 0;

    /* Compute the prescaler value to have TIM1 counter clock equal to 48MHz */
    uhPrescalerValue = (uint32_t)(SystemCoreClock / (2 * OV5640XCLK_FREQ * 2)) - 1;

    /*##-1- Configure the TIM peripheral #######################################*/
    /* -----------------------------------------------------------------------
    TIM1 Configuration: generate 4 PWM signals with 4 different duty cycles.

      In this example TIM1 input clock (TIM1CLK) is set to APB2 clock (PCLK2),
      since APB2 prescaler is equal to 2.
        TIM1CLK = 2*PCLK2
        PCLK2 = HCLK/2 as AHB Clock divider is set to RCC_HCLK_DIV2
        => TIM1CLK = HCLK = SystemCoreClock/2

      To get TIM1 counter clock at 48 MHz, the prescaler is computed as follows:
         Prescaler = (TIM1CLK / TIM1 counter clock) - 1
         Prescaler = ((SystemCoreClock) /(2*48 MHz)) - 1

      To get TIM1 output clock at 24 MHz, the period (ARR)) is computed as follows:
         ARR = (TIM1 counter clock / TIM1 output clock) - 1
             = 48MHz / 24MHz - 1 = 1

      TIM1 Channel2 duty cycle = (TIM1_CCR2/ TIM1_ARR + 1)* 100 = 1 / (1 + 1) = 50%

      Note:
       SystemCoreClock variable holds HCLK frequency and is defined in system_stm32h7xx.c file.
       Each time the core clock (HCLK) changes, user had to update SystemCoreClock
       variable value. Otherwise, any configuration based on this variable will be incorrect.
       This variable is updated in three ways:
        1) by calling CMSIS function SystemCoreClockUpdate()
        2) by calling HAL API function HAL_RCC_GetSysClockFreq()
        3) each time HAL_RCC_ClockConfig() is called to configure the system clock frequency
    ----------------------------------------------------------------------- */

    /* Initialize TIMx peripheral as follows:
       + Prescaler = (SystemCoreClock / (2*20000000)) - 1
       + Period = (1000 - 1)
       + ClockDivision = 0
       + Counter direction = Up
     */

    ov5640_tim_handle.Instance = OV5640XCLK;

    ov5640_tim_handle.Init.Prescaler = uhPrescalerValue;
    ov5640_tim_handle.Init.Period = 1;
    ov5640_tim_handle.Init.ClockDivision = 0;
    ov5640_tim_handle.Init.CounterMode = TIM_COUNTERMODE_UP;
    ov5640_tim_handle.Init.RepetitionCounter = 0;
    if (HAL_TIM_PWM_Init(&ov5640_tim_handle) != HAL_OK)
    {
        /* Initialization Error */
        Error_Handler();
    }

    /*##-2- Configure the PWM channels #########################################*/
    /* Common configuration for all channels */
    sConfig.OCMode = TIM_OCMODE_PWM1;
    sConfig.OCPolarity = TIM_OCPOLARITY_HIGH;
    sConfig.OCFastMode = TIM_OCFAST_DISABLE;
    sConfig.OCNPolarity = TIM_OCNPOLARITY_HIGH;
    sConfig.OCNIdleState = TIM_OCNIDLESTATE_RESET;

    sConfig.OCIdleState = TIM_OCIDLESTATE_RESET;

    /* Set the pulse value for channel 2 */
    sConfig.Pulse = 1;
    if (HAL_TIM_PWM_ConfigChannel(&ov5640_tim_handle, &sConfig, TIM_CHANNEL_2) != HAL_OK)
    {
        /* Configuration Error */
        Error_Handler();
    }

    /* Start channel 2 */
    if (HAL_TIM_PWM_Start(&ov5640_tim_handle, TIM_CHANNEL_2) != HAL_OK)
    {
        /* PWM Generation Error */
        Error_Handler();
    }

    return 0;
}